package io.github.yotta.logger.core.utils;

import java.lang.reflect.Method;

public class MethodUtil {
    public static String getMethodKey(Method method) {
        StringBuilder sb = new StringBuilder();
        sb.append(method.getDeclaringClass().getName());
        sb.append('.');
        sb.append(method.getName());
        sb.append(getMethodDescriptor(method));
        return sb.toString();
    }

    public static String getMethodKeyWithReturnTypeAsLastParameter(Method method, Class targetClass) {
        StringBuilder sb = new StringBuilder();
        sb.append(targetClass.getName());
        sb.append('.');
        sb.append(method.getName());
        sb.append(getMethodDescriptorWithReturnTypeAsLastParameter(method));
        return sb.toString();
    }

    public static String getMethodDescriptor(Method m) {
        Class[] parameters = m.getParameterTypes();
        StringBuilder buf = new StringBuilder();
        buf.append('(');

        for (int i = 0; i < parameters.length; ++i) {
            getDescriptor(buf, parameters[i]);
        }

        buf.append(')');
        getDescriptor(buf, m.getReturnType());
        return buf.toString();
    }

    public static String getMethodDescriptorWithReturnTypeAsLastParameter(Method m) {
        Class[] parameters = m.getParameterTypes();
        StringBuilder buf = new StringBuilder();
        buf.append('(');

        for (int i = 0; i < parameters.length - 1; ++i) {
            getDescriptor(buf, parameters[i]);
        }

        buf.append(')');
        getDescriptor(buf, parameters[parameters.length - 1]);
        return buf.toString();
    }

    public static int lastParameterIndexOf(Class[] parameters, Class targetType) {
        for (int i = parameters.length - 1; i >= 0; --i) {
            if (parameters[i].equals(targetType)) {
                return i;
            }
        }

        return -1;
    }

    private static void getDescriptor(StringBuilder buf, Class c) {
        Class d;
        for (d = c; !d.isPrimitive(); d = d.getComponentType()) {
            if (!d.isArray()) {
                buf.append('L');
                String name = d.getName();
                int len = name.length();

                for (int i = 0; i < len; ++i) {
                    char car = name.charAt(i);
                    buf.append(car == '.' ? '/' : car);
                }

                buf.append(';');
                return;
            }

            buf.append('[');
        }

        char car;
        if (d == Integer.TYPE) {
            car = 'I';
        } else if (d == Void.TYPE) {
            car = 'V';
        } else if (d == Boolean.TYPE) {
            car = 'Z';
        } else if (d == Byte.TYPE) {
            car = 'B';
        } else if (d == Character.TYPE) {
            car = 'C';
        } else if (d == Short.TYPE) {
            car = 'S';
        } else if (d == Double.TYPE) {
            car = 'D';
        } else if (d == Float.TYPE) {
            car = 'F';
        } else {
            car = 'J';
        }

        buf.append(car);
    }
}
